/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package modules.enderecamento.bo;

import java.awt.Desktop;
import java.io.File;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;
import modules.enderecamento.models.dto.Usuario;
import modules.enderecamento.util.BoxPanel;
import modules.enderecamento.util.Funcoes;
import net.sf.jasperreports.engine.JRException;

import net.sf.jasperreports.engine.JRResultSetDataSource;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import java.util.HashMap;
import java.util.Map;
import modules.enderecamento.gui.Aplicativo;
import modules.enderecamento.models.dao.AbstractDAO;
import modules.enderecamento.models.dto.Palete;
import modules.enderecamento.models.dto.Rua;
import modules.enderecamento.security.WMSSession;
import net.sf.jasperreports.engine.JasperExportManager;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.util.JRLoader;

/**
 *
 * @author clezio
 */
public class RelatorioBO {

    private File logo;

    public RelatorioBO() {
        this.logo = new File("img/logo.png");
    }

    public void apuracaoPorEndereco() {
        String sql = "select rua.nome as rua, pa.id as palete,pr.codigo as produto_codigo,pr.descricao as produto_descricao, e.quantidade as quantidade from enderecamentos e "
                + "join produtos pr on (e.produto_id = pr.id) "
                + "join paletes pa on (e.palete_id = pa.id) "
                + "join ruas rua on (pa.rua_id = rua.id)";
        try {
            String nameRelatorio = "relatorios/groupByRua.jasper";
            Map parameters = new HashMap();
            parameters.put("Title", "Relatório de Apuração por Endereço");
            parameters.put("logo", logo);
            obterRelatorio(nameRelatorio, sql, parameters, "Apuração por Endereço");
        } catch (Exception ex) {
            Funcoes.registrarLog(ex);
            Logger.getLogger(RelatorioBO.class.getName()).log(Level.SEVERE, null, ex);
            BoxPanel.showMessageDialog(null, "Ocorreu um erro na geração do relatório. Por favor tente novamente.");

        }
    }

    public void apuracaoGeral() {
        String sql = "select pr.codigo as produto_codigo,pr.descricao as produto_descricao, sum(e.quantidade) as quantidade from enderecamentos e "
                + "join produtos pr on (e.produto_id = pr.id) "
                + "join paletes pa on (e.palete_id = pa.id) "
                + "join ruas rua on (pa.rua_id = rua.id) "
                + "group by pr.codigo,pr.descricao";
        try {
            String nameRelatorio = "relatorios/apuracaoGeral.jasper";
            Map parameters = new HashMap();
            parameters.put("Title", "Relatório de Apuração de Estoque");
            parameters.put("logo", logo);

            obterRelatorio(nameRelatorio, sql, parameters, "Apuração de Estoque");
        } catch (Exception ex) {
            Funcoes.registrarLog(ex);
            Logger.getLogger(RelatorioBO.class.getName()).log(Level.SEVERE, null, ex);
            BoxPanel.showMessageDialog(null, "Ocorreu um erro na geração do relatório. Por favor tente novamente.");

        }
    }

    public void espacoFisicoRua(Rua ruaParametro, Integer percentualDisponivel, Integer percentualOcupado) {
        String where = " 1 = 1";
        String having = null;
        String nameRelatorio = "relatorios/espacoFisicoRua.jasper";
        Map parameters = new HashMap();
        parameters.put("Title", "Relatório de Ocupação por Rua");
        parameters.put("logo", logo);

        if (ruaParametro != null) {
            where += " AND r.id = " + ruaParametro.getId();
            parameters.put("ruaFiltro", ruaParametro.getNome());
        }
        if (percentualDisponivel != null) {
            having = "HAVING ((r.quantidade_paletes - count(rua_id)) * 100 / r.quantidade_paletes) >= " + percentualDisponivel + " ";
            parameters.put("percentualDisponivelFiltro", percentualDisponivel);
        } else if (percentualOcupado != null) {
            having = "HAVING ((count(rua_id)) * 100 / r.quantidade_paletes) >= " + percentualOcupado + " ";
            parameters.put("percentualOcupadoFiltro", percentualOcupado);
        }

        String sql = "select r.nome,r.quantidade_paletes as capacidade, count(rua_id) as ocupado,(r.quantidade_paletes - count(rua_id)) as disponivel from ruas r "
                + "left join paletes pa on (pa.rua_id = r.id) "
                + "where " + where + " "
                + "group by r.nome,r.quantidade_paletes ";
        if (having != null) {
            sql += having;
        }
        sql += "order by r.nome";
        try {
            obterRelatorio(nameRelatorio, sql, parameters, "Relatório de Ocupação por Rua");
        } catch (Exception ex) {
            Funcoes.registrarLog(ex);
            Logger.getLogger(RelatorioBO.class.getName()).log(Level.SEVERE, null, ex);
            BoxPanel.showMessageDialog(null, "Ocorreu um erro na geração do relatório. Por favor tente novamente.");

        }
    }

    public void espacoFisicoPalete(Rua ruaParametro, Palete palete, Integer percentualDisponivel, Integer percentualOcupado) {
        String where = " 1 = 1";
        String having = null;
        String nameRelatorio = "relatorios/espacoFisicoPalete.jasper";
        Map parameters = new HashMap();
        parameters.put("Title", "Relatório de Ocupação por Palete");
        parameters.put("logo", logo);
        if (ruaParametro != null) {
            where += " AND r.id = " + ruaParametro.getId();
            parameters.put("ruaFiltro", ruaParametro.getNome());
        }

        if (palete != null) {
            where += " AND pa.id = " + palete.getId();
            parameters.put("paleteFiltro", palete.getId());
        }

        if (percentualDisponivel != null) {
            having = "HAVING ((pa.cubagem - coalesce(sum(p.largura/100*p.altura/100*p.comprimento/100*e.quantidade),0)) * 100 / pa.cubagem) >= " + percentualDisponivel + " ";
            parameters.put("percentualDisponivelFiltro", percentualDisponivel);
        } else if (percentualOcupado != null) {
            having = "HAVING ((coalesce(sum(p.largura/100*p.altura/100*p.comprimento/100*e.quantidade),0)) * 100 / pa.cubagem) >=  " + percentualOcupado + " ";
            parameters.put("percentualOcupadoFiltro", percentualOcupado);
        }
        String sql = "select pa.id as palete,coalesce(r.nome,'Nenhuma') as rua, pa.cubagem as capacidade, coalesce(sum(p.largura/100*p.altura/100*p.comprimento/100*e.quantidade),0) as ocupado, "
                + "(pa.cubagem - coalesce(sum(p.largura/100*p.altura/100*p.comprimento/100*e.quantidade),0)) as disponivel "
                + "from enderecamentos e join produtos p on(e.produto_id = p.id)"
                + "right join paletes pa on(e.palete_id = pa.id)"
                + "left join ruas r on(pa.rua_id = r.id) "
                + "where " + where + " "
                + "group by pa.id,r.nome,pa.cubagem ";
        if (having != null) {
            sql += having;
        }
        sql += "order by pa.id";
        try {
            obterRelatorio(nameRelatorio, sql, parameters, "Relatório de Ocupação por Palete");
        } catch (Exception ex) {
            Funcoes.registrarLog(ex);
            Logger.getLogger(RelatorioBO.class.getName()).log(Level.SEVERE, null, ex);
            BoxPanel.showMessageDialog(null, "Ocorreu um erro na geração do relatório. Por favor tente novamente.");

        }
    }

    private void obterRelatorio(String nameRelatorio, String sql, Map parametros, String namePdf) throws JRException {
        Thread t = new Thread(new RunRelatorio(nameRelatorio, sql, parametros, namePdf));
        t.start();
    }

    public void produtosAcabados(Usuario usr1, Usuario usr2) {
        String nameRelatorio = "relatorios/posicaoEstoque.jasper";
        Map parameters = new HashMap();
        parameters.put("Title", "Relatório de Produtos Acabados");
        parameters.put("logo", logo);
        if(usr1 != null){
            parameters.put("assinatura1", usr1.getNome());
            if(usr1.getCargo() != null){
                parameters.put("cargo1", usr1.getCargo().getNome());
            }
        }
        if(usr2 != null){
            parameters.put("assinatura2", usr2.getNome());
            if(usr2.getCargo() != null){
                parameters.put("cargo2", usr2.getCargo().getNome());
            }
        }


        String sql = "select pr.codigo as produto_codigo,pr.descricao as produto_descricao, coalesce(sum(e.quantidade),0) as quantidade, "
                + "gp.nome as grupo, coalesce(gpParent.nome,gp.nome) as grupo_parent "
                + "from produtos pr "
                + "left join enderecamentos e on (e.produto_id = pr.id) "
                + "left join paletes pa on (e.palete_id = pa.id) "
                + "left join ruas rua on (pa.rua_id = rua.id) "
                + "left join grupos_produtos gp on (pr.grupos_produto_id = gp.id) "
                + "left join grupos_produtos gpParent on (gp.grupos_produto_id = gpParent.id) "
                + "group by pr.codigo,pr.descricao,gp.nome, gpParent.nome order by gpParent.nome, gp.nome ";

        try {
            obterRelatorio(nameRelatorio, sql, parameters, "Relatório de Produtos Acabados");
        } catch (Exception ex) {
            Funcoes.registrarLog(ex);
            Logger.getLogger(RelatorioBO.class.getName()).log(Level.SEVERE, null, ex);
            BoxPanel.showMessageDialog(null, "Ocorreu um erro na geração do relatório. Por favor tente novamente.");

        }
    }

    public class RunRelatorio implements Runnable {

        private String namePdf;
        private String nameRelatorio;
        private Map parameters;
        private String sql;

        public RunRelatorio(String nameRelatorio, String sql, Map parameters, String namePdf){
            this.namePdf = namePdf;
            this.nameRelatorio = nameRelatorio;
            this.parameters = parameters;
            this.sql = sql;
        }

        @Override
        public void run() {
            Connection conexao = null;
            try {
                Aplicativo aplicativo = WMSSession.getInstance().getAplicativo();
                conexao = new AbstractDAO().obterConexao();
                JRResultSetDataSource jrRS = new JRResultSetDataSource(
                        conexao.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY).executeQuery(sql));
                // Carrega os arquivos jasper
                aplicativo.getLbNotificacao().setText("Carregando relatório");
                JasperReport relatorioJasper = (JasperReport) JRLoader.loadObject(nameRelatorio);
                JasperPrint jasperPrint = JasperFillManager.fillReport(relatorioJasper, parameters, jrRS);
                aplicativo.getLbNotificacao().setText("Gerando arquivo pdf");
                File file = new File("tmp/" + namePdf + ".pdf");
                if (file.exists()) {
                    if (!file.delete()) {
                        conexao.close();
                        aplicativo.getLbNotificacao().setText("");
                        BoxPanel.showMessageDialog(null, "Possivelmente existe um relatório aberto. \r\nÉ necessário fechá-lo antes de gerar um novo relatório.");
                        return;
                    }
                }
                JasperExportManager.exportReportToPdfFile(jasperPrint, "tmp/" + namePdf + ".pdf");
                conexao.close();
                Desktop desktop = java.awt.Desktop.getDesktop();
                desktop.open(new File("tmp/" + namePdf + ".pdf"));
//                Thread.sleep(2000);
                aplicativo.getLbNotificacao().setText("");
                
            } catch (Exception ex) {
                JRException e = (JRException) ex;
                Logger.getLogger(RelatorioBO.class.getName()).log(Level.SEVERE, null, e);
            } finally {
                try {
                    conexao.close();
                } catch (SQLException ex) {
                    Logger.getLogger(RelatorioBO.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
    }
}
